home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
winsock
/
twnsck12.zip
/
SRC\WINSOCK.C
< prev
next >
Wrap
Text File
|
1994-12-03
|
49KB
|
2,047 lines
/*
* TwinSock - "Troy's Windows Sockets"
*
* Copyright (C) 1994 Troy Rollo <troy@cbme.unsw.EDU.AU>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <winsock.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "twinsock.h"
#include "tx.h"
#ifdef __MSDOS__
#define PORTSWAP(x) ntohs(x)
#else
#define PORTSWAP(x) ntohl(x)
#endif
static int iErrno = 0;
static short idNext = 0;
static struct per_task *pptList = 0;
static struct per_socket *ppsList = 0;
static struct tx_queue *ptxqList = 0;
HWND hwndManager = 0;
BOOL bEstablished = 0;
static void FireAsyncRequest(struct tx_queue *ptxq);
void _export
RegisterManager(HWND hwnd)
{
hwndManager = hwnd;
}
void _export
SetInitialised(void)
{
bEstablished = TRUE;
}
void
CopyDataIn( void *pvSource,
enum arg_type at,
void *pvDest,
int nLen)
{
switch(at)
{
case AT_Int16:
case AT_Int16Ptr:
*(short *) pvDest = ntohs(*(short *) pvSource);
break;
case AT_Int32:
case AT_Int32Ptr:
*(short *) pvDest = ntohl(*(short *) pvSource);
break;
case AT_Char:
*(char *) pvDest = *(char *) pvSource;
break;
case AT_GenPtr:
case AT_String:
memcpy(pvDest, pvSource, nLen);
break;
}
}
void
CopyDataOut( void *pvDest,
enum arg_type at,
void *pvSource,
int nLen)
{
switch(at)
{
case AT_Int16Ptr:
case AT_Int16:
*(short *) pvDest = htons(*(short *) pvSource);
break;
case AT_Int32:
case AT_Int32Ptr:
*(short *) pvDest = htonl(*(short *) pvSource);
break;
case AT_Char:
*(char *) pvDest = *(char *) pvSource;
break;
case AT_GenPtr:
case AT_String:
memcpy(pvDest, pvSource, nLen);
break;
}
}
static struct per_task *
GetAnotherTaskInfo(HTASK htask)
{
struct per_task *ppt;
for (ppt = pptList; ppt; ppt = ppt->pptNext)
{
if (ppt->htask == htask)
return ppt;
}
iErrno = WSANOTINITIALISED;
return 0;
}
static struct per_task *
GetTaskInfo(void)
{
return GetAnotherTaskInfo(GetCurrentTask());
}
static struct per_socket *
GetSocketInfo(SOCKET s)
{
struct per_socket *pps;
for (pps = ppsList; pps; pps = pps->ppsNext)
{
if (pps->s == s)
return pps;
}
iErrno = WSAENOTSOCK;
return 0;
}
static void
Notify(struct per_socket *pps,
int iCode)
{
if (pps->iEvents & iCode)
PostMessage(pps->hWnd, pps->wMsg, pps->s, WSAMAKESELECTREPLY(iCode, 0));
}
static struct per_socket *
NewSocket(struct per_task *ppt, SOCKET s)
{
struct per_socket *ppsNew;
ppsNew = (struct per_socket *) malloc(sizeof(struct per_socket));
ppsNew->s = s;
ppsNew->iFlags = 0;
ppsNew->pdIn = 0;
ppsNew->pdOut = 0;
ppsNew->htaskOwner = ppt->htask;
ppsNew->ppsNext = ppsList;
ppsNew->iEvents = 0;
ppsList = ppsNew;
return ppsNew;
}
static void SendEarlyClose(SOCKET s);
static void
RemoveSocket(struct per_socket *pps)
{
struct per_socket **ppps, *ppsParent;
struct data **ppd, *pd;
/* If our parent has noticed we're here, we need to remove ourselves
* from the list of sockets awaiting acception.
*/
for (ppsParent = ppsList; ppsParent; ppsParent = ppsParent->ppsNext)
{
if (!(ppsParent->iFlags & PSF_ACCEPT))
continue;
for (ppd = &ppsParent->pdIn; *ppd; ppd = &(*ppd)->pdNext)
{
if ((*ppd)->pchData == (char *) pps)
{
pd = *ppd;
*ppd = pd->pdNext;
free(pd);
}
}
}
/* Find our own position in the list */
for (ppps = &ppsList; *ppps; ppps = &(*ppps)->ppsNext)
{
if (*ppps == pps)
{
*ppps = pps->ppsNext;
/* If we have unacknowledged children, kill them */
while (pps->pdIn)
{
pd = pps->pdIn;
pps->pdIn = pd->pdNext;
if (pps->iFlags & PSF_ACCEPT)
{
SendEarlyClose(((struct per_socket *) pd->pchData)->s);
RemoveSocket((struct per_socket *) pd->pchData);
}
else
{
free(pd->pchData);
}
free(pd);
}
free(pps);
return;
}
}
}
static void
DataReceived(SOCKET s, void *pvData, int nLen, enum Functions ft)
{
struct data *pdNew, **ppdList;
struct per_socket *pps, *ppsNew;
struct per_task *ppt;
int ns;
pps = GetSocketInfo(s);
if (!pps)
{
if (ft == FN_Accept)
{
nLen -= sizeof(struct sockaddr_in);
pvData = (char *) pvData + sizeof(struct sockaddr_in);
if (nLen == sizeof(long))
ns = ntohl(*(long *) pvData);
else
ns = ntohs(*(short*) pvData);
SendEarlyClose(ns);
}
return;
}
for (ppdList = &pps->pdIn; *ppdList; ppdList = &(*ppdList)->pdNext);
pdNew = (struct data *) malloc(sizeof(struct data));
pdNew->sin = *(struct sockaddr_in *) pvData;
pdNew->sin.sin_family = ntohs(pdNew->sin.sin_family);
nLen -= sizeof(struct sockaddr_in);
pvData = (char *) pvData + sizeof(struct sockaddr_in);
pdNew->pdNext = 0;
pdNew->nUsed = 0;
*ppdList = pdNew;
/* Note that the calls to Notify below should *really*
* only be made if the data gets put at the head of the
* queue, but some telnet implementations miss notifications
* and this screws us right up. By putting in additional
* notifications we at least have a chance of recovery.
*/
if (pps->iFlags & PSF_ACCEPT)
{
pdNew->iLen = 0;
if (nLen == sizeof(long))
ns = ntohl(*(long *) pvData);
else
ns = ntohs(*(short*) pvData);
ppt = GetAnotherTaskInfo(pps->htaskOwner);
ppsNew = NewSocket(ppt, ns);
pdNew->pchData = (char *) ppsNew;
ppsNew->iFlags |= PSF_CONNECT;
Notify(pps, FD_ACCEPT);
}
else
{
pdNew->iLen = nLen;
pdNew->pchData = (char *) malloc(nLen);
memcpy(pdNew->pchData, pvData, nLen);
Notify(pps, nLen ? FD_READ : FD_CLOSE);
}
}
static BOOL
StartBlocking(struct per_task *ppt)
{
if (ppt->bBlocking)
{
iErrno = WSAEINPROGRESS;
return FALSE;
}
else
{
ppt->bBlocking = TRUE;
ppt->bCancel = FALSE;
return TRUE;
}
}
static void
EndBlocking(struct per_task *ppt)
{
ppt->bBlocking = FALSE;
}
static BOOL
FlushMessages(struct per_task *ppt)
{
MSG msg;
BOOL ret;
if (ppt->lpBlockFunc)
return ((BOOL far pascal (*)()) ppt->lpBlockFunc)();
ret = (BOOL) PeekMessage(&msg,0,0,0,PM_REMOVE);
if (ret)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
/* Some poorly behaved applications quit without
* checking the return value of WSACancel. It
* *can* fail.
*/
if (msg.message == WM_QUIT)
ppt->bCancel = TRUE;
}
return ret;
}
static void
RemoveTXQ(struct tx_queue *ptxq)
{
struct tx_queue **pptxq;
for (pptxq = &ptxqList; *pptxq; pptxq = &((*pptxq)->ptxqNext))
{
if (*pptxq == ptxq)
{
*pptxq = ptxq->ptxqNext;
free(ptxq->ptxr);
free(ptxq);
return;
}
}
}
static void
RemoveTask(struct per_task *ppt)
{
struct per_task **pppt;
for (pppt = &pptList; *pppt; pppt = &((*pppt)->pptNext))
{
if (*pppt == ppt)
{
*pppt = ppt->pptNext;
free(ppt);
}
}
};
void far _export
ResponseReceived(struct tx_request *ptxr)
{
int nLen;
int id;
struct tx_queue *ptxq;
enum Functions ft;
ft = (enum Functions) ntohs(ptxr->iType);
id = ntohs(ptxr->id);
nLen = ntohs(ptxr->nLen);
if (ft == FN_Data || ft == FN_Accept)
{
DataReceived(id, ptxr->pchData, nLen - sizeof(short) * 5, ft);
return;
}
for (ptxq = ptxqList; ptxq; ptxq = ptxq->ptxqNext)
{
if (ptxq->id == id)
{
memcpy(ptxq->ptxr, ptxr, nLen);
ptxq->bDone = TRUE;
if (ptxq->pchLocation)
FireAsyncRequest(ptxq);
return;
}
}
}
static struct tx_queue *
TransmitFunction(struct transmit_function *ptf)
{
int i;
int nSize = sizeof(short) * 5;
struct tx_request *ptxr;
struct tx_queue *ptxq, **pptxq;
int iOffset;
for (i = 0; i < ptf->nArgs; i++)
nSize += ptf->pfaList[i].iLen + sizeof(short) * 2;
nSize += ptf->pfaResult->iLen + sizeof(short) * 2;
ptxr = (struct tx_request *) malloc(nSize);
ptxr->iType = htons((short) ptf->fn);
ptxr->nArgs = htons((short) ptf->nArgs);
ptxr->nError = 0;
ptxr->nLen = htons((short) nSize);
ptxr->id = htons(idNext);
for (iOffset = i = 0; i < ptf->nArgs; i++)
{
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaList[i].at);
iOffset += 2;
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaList[i].iLen);
iOffset += 2;
CopyDataOut( ptxr->pchData + iOffset,
ptf->pfaList[i].at,
ptf->pfaList[i].pvData,
ptf->pfaList[i].iLen);
iOffset += ptf->pfaList[i].iLen;
}
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaResult->at);
iOffset += 2;
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaResult->iLen);
iOffset += 2;
CopyDataOut( ptxr->pchData + iOffset,
ptf->pfaResult->at,
ptf->pfaResult->pvData,
ptf->pfaResult->iLen);
iOffset += ptf->pfaResult->iLen;
ptxq = (struct tx_queue *) malloc(sizeof(struct tx_queue));
ptxq->ptxqNext = 0;
ptxq->id = idNext;
ptxq->ptxr = ptxr;
ptxq->bDone = 0;
ptxq->hwnd = 0;
ptxq->pchLocation = 0;
ptxq->wMsg = 0;
idNext++;
for (pptxq = &ptxqList; *pptxq; pptxq = &((*pptxq)->ptxqNext));
*pptxq = ptxq;
SendMessage(hwndManager, WM_USER, nSize, (LPARAM) ptxr);
return ptxq;
};
static void
SendEarlyClose(SOCKET s)
{
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
int nReturn;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Close, 1, pfaArgs, pfaReturn);
RemoveTXQ(TransmitFunction(&tf));
}
static void
SetErrorResult(struct func_arg *pfaResult)
{
switch (pfaResult->at)
{
case AT_Int16:
*(short *) pfaResult->pvData = -1;
break;
case AT_Int32:
*(long *) pfaResult->pvData = -1;
break;
case AT_Char:
*(char *) pfaResult->pvData = -1;
break;
case AT_Int16Ptr:
case AT_Int32Ptr:
case AT_String:
case AT_GenPtr:
*(void **) pfaResult->pvData = 0;
break;
}
}
static int TransmitFunctionAndBlock(
struct per_task *ppt,
struct transmit_function *ptf)
{
struct tx_queue *ptxq;
struct tx_request *ptxr;
int i, iOffset;
BOOL bError = FALSE;
if (!StartBlocking(ppt))
{
iErrno = WSAEINPROGRESS;
SetErrorResult(ptf->pfaResult);
return 0;
}
ptxq = TransmitFunction(ptf);
ptxr = ptxq->ptxr;
while (!ptxq->bDone)
{
FlushMessages(ppt);
if (ppt->bCancel)
{
iErrno = WSAEINTR;
RemoveTXQ(ptxq);
SetErrorResult(ptf->pfaResult);
EndBlocking(ppt);
return 0;
}
}
if (ptxq->ptxr->nError)
{
iErrno = ntohs(ptxq->ptxr->nError);
SetErrorResult(ptf->pfaResult);
bError = TRUE;
}
else
{
for (iOffset = i = 0; i < ptf->nArgs; i++)
{
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaList[i].at);
iOffset += 2;
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaList[i].iLen);
iOffset += 2;
if (!ptf->pfaList[i].bConstant)
CopyDataIn( ptxr->pchData + iOffset,
ptf->pfaList[i].at,
ptf->pfaList[i].pvData,
ptf->pfaList[i].iLen);
iOffset += ptf->pfaList[i].iLen;
}
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaResult->at);
iOffset += 2;
*(short *) (ptxr->pchData + iOffset) = htons((short) ptf->pfaResult->iLen);
iOffset += 2;
CopyDataIn( ptxr->pchData + iOffset,
ptf->pfaResult->at,
ptf->pfaResult->pvData,
ptf->pfaResult->iLen);
}
RemoveTXQ(ptxq);
EndBlocking(ppt);
return bError ? 0 : 1;
}
static void
CopyHostEnt(struct per_task *ppt)
{
int iLocation;
int i;
int nAddrs;
ppt->he.h_addrtype = ntohs(*(short *) ppt->achHostEnt);
ppt->he.h_length = ntohs(*(short *) (ppt->achHostEnt + sizeof(short)));
nAddrs = ntohs(*(short *) (ppt->achHostEnt + sizeof(short) * 2));
iLocation = sizeof(short) * 3;
for (i = 0; i < nAddrs; i++)
{
if (i < MAX_ALTERNATES - 1)
ppt->apchHostAddresses[i] = ppt->achHostEnt + iLocation;
iLocation += 4;
}
if (nAddrs < MAX_ALTERNATES - 1)
ppt->apchHostAddresses[nAddrs] = 0;
else
ppt->apchHostAddresses[MAX_ALTERNATES - 1] = 0;
ppt->he.h_addr_list = ppt->apchHostAddresses;
ppt->he.h_name = ppt->achHostEnt + iLocation;
iLocation += strlen(ppt->achHostEnt + iLocation)+ 1;
for (i = 0; ppt->achHostEnt[iLocation] && i < MAX_ALTERNATES - 1; i++)
{
ppt->apchHostAlii[i] = ppt->achHostEnt + iLocation;
iLocation += strlen(ppt->achHostEnt + iLocation)+ 1;
}
ppt->apchHostAlii[i] = 0;
ppt->he.h_aliases = ppt->apchHostAlii;
ppt->he.h_addr_list = ppt->apchHostAddresses;
}
static int
CopyHostEntTo(struct per_task *ppt, char *pchData)
{
int i;
int nAddrs;
struct hostent *phe;
char *pchOld;
int nAlii;
CopyHostEnt(ppt);
phe = (struct hostent *) pchData;
memcpy(phe, &ppt->he, sizeof(ppt->he));
pchData += sizeof(*phe);
for (nAddrs = 0; phe->h_addr_list[nAddrs]; nAddrs++);
for (nAlii = 0; phe->h_aliases[nAlii]; nAlii++);
memcpy(pchData, phe->h_addr_list, sizeof(char *) * (nAddrs + 1));
phe->h_addr_list = (char **) pchData;
pchData += sizeof(char *) * (nAddrs + 1);
memcpy(pchData, phe->h_aliases, sizeof(char *) * (nAddrs + 1));
phe->h_aliases = (char **) pchData;
pchData += sizeof(char *) * (nAddrs + 1);
pchOld = phe->h_addr_list[0];
memcpy(pchData, pchOld, 4 * nAddrs);
for (i = 0; i < nAddrs; i++)
phe->h_addr_list[i] = phe->h_addr_list[i] - pchOld + pchData;
pchData += 4 * nAddrs;
strcpy(pchData, phe->h_name);
phe->h_name = pchData;
pchData += strlen(pchData) + 1;
for (i = 0; i < nAlii; i++)
{
strcpy(pchData, phe->h_aliases[i]);
phe->h_aliases[i] = pchData;
pchData += strlen(pchData) + 1;
}
return (pchData - (char *) phe);
}
static void
CopyServEnt(struct per_task *ppt)
{
int iLocation;
int i;
/* Note that s_port is needed in network byte order */
ppt->se.s_port = *(short *) ppt->achServEnt;
iLocation = sizeof(short);
ppt->se.s_proto = ppt->achServEnt + iLocation;
iLocation += strlen(ppt->achServEnt + iLocation) + 1;
ppt->se.s_name = ppt->achServEnt + iLocation;
iLocation += strlen(ppt->achServEnt + iLocation) + 1;
for (i = 0; ppt->achServEnt[iLocation] && i < MAX_ALTERNATES - 1; i++)
{
ppt->apchServAlii[i] = ppt->achServEnt + iLocation;
iLocation += strlen(ppt->achServEnt + iLocation) + 1;
}
ppt->apchServAlii[i] = 0;
ppt->se.s_aliases = ppt->apchServAlii;
}
static int
CopyServEntTo(struct per_task *ppt, char *pchData)
{
int i;
int nAlii;
struct servent *pse;
CopyServEnt(ppt);
pse = (struct servent *) pchData;
memcpy(pse, &ppt->se, sizeof(ppt->se));
pchData += sizeof(*pse);
for (nAlii = 0; pse->s_aliases[nAlii]; nAlii++);
memcpy(pchData, pse->s_aliases, sizeof(char *) * (nAlii + 1));
pse->s_aliases = (char **) pchData;
pchData += sizeof(char *) * (nAlii + 1);
strcpy(pchData, ppt->se.s_name);
ppt->se.s_name = pchData;
pchData += strlen(pchData) + 1;
strcpy(pchData, ppt->se.s_proto);
ppt->se.s_proto = pchData;
pchData += strlen(pchData) + 1;
for (i = 0; i < nAlii; i++)
{
strcpy(pchData, pse->s_aliases[i]);
pse->s_aliases[i] = pchData;
pchData += strlen(pchData) + 1;
}
return (pchData - (char *) pse);
}
static void
CopyProtoEnt(struct per_task *ppt)
{
int iLocation;
int i;
int nAddrs;
ppt->pe.p_proto = ntohs(*(short *) ppt->achProtoEnt);
iLocation = sizeof(short);
ppt->pe.p_name = ppt->achProtoEnt + iLocation;
iLocation += strlen(ppt->achProtoEnt + iLocation) + 1;
for (i = 0; ppt->achProtoEnt[iLocation] && i < MAX_ALTERNATES - 1; i++)
{
ppt->apchProtoAlii[i] = ppt->achProtoEnt + iLocation;
iLocation += strlen(ppt->achProtoEnt + iLocation) + 1;
}
ppt->apchProtoAlii[i] = 0;
ppt->pe.p_aliases = ppt->apchProtoAlii;
}
static int
CopyProtoEntTo(struct per_task *ppt, char *pchData)
{
int iLocation;
int i;
int nAlii;
struct protoent *ppe;
CopyProtoEnt(ppt);
ppe = (struct protoent *) pchData;
memcpy(ppe, &ppt->pe, sizeof(ppt->pe));
pchData += sizeof(*ppe);
for (nAlii = 0; ppe->p_aliases[nAlii]; nAlii++);
memcpy(pchData, ppe->p_aliases, sizeof(char *) * (nAlii + 1));
ppe->p_aliases = (char **) pchData;
pchData += sizeof(char *) * (nAlii + 1);
strcpy(pchData, ppe->p_name);
ppe->p_name = pchData;
pchData += strlen(pchData) + 1;
for (i = 0; i < nAlii; i++)
{
strcpy(pchData, ppe->p_aliases[i]);
ppe->p_aliases[i] = pchData;
pchData += strlen(pchData) + 1;
}
return (pchData - (char *) ppe);
}
SOCKET pascal far _export
accept(SOCKET s, struct sockaddr FAR *addr,
int FAR *addrlen)
{
struct per_task *ppt;
struct per_socket *pps, *ppsNew;
struct data *pd;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
if (!(pps->iFlags & PSF_ACCEPT))
{
iErrno = WSAEINVAL;
return -1;
}
if (!pps->pdIn && (pps->iFlags & PSF_NONBLOCK))
{
iErrno = WSAEWOULDBLOCK;
return -1;
}
if (!StartBlocking(ppt))
return -1;
while (!pps->pdIn)
{
FlushMessages(ppt);
if (ppt->bCancel)
{
iErrno = WSAEINTR;
EndBlocking(ppt);
return -1;
}
}
pd = pps->pdIn;
if (addr && addrlen)
{
memcpy(addr, &pd->sin, sizeof(pd->sin));
*addrlen = sizeof(pd->sin);
}
ppsNew = (struct per_socket *) pd->pchData;
pps->pdIn = pd->pdNext;
free(pd);
if (pps->pdIn)
Notify(pps, FD_ACCEPT);
EndBlocking(ppt);
return ppsNew->s;
}
int pascal far _export
bind(SOCKET s, const struct sockaddr FAR *addr, int namelen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
struct sockaddr *psa;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!GetSocketInfo(s))
return -1;
psa = (struct sockaddr *) malloc(namelen);
memcpy(psa, addr, namelen);
psa->sa_family = htons(psa->sa_family);
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_CARGS(pfaArgs[1], AT_GenPtr, psa, namelen );
INIT_ARGS(pfaArgs[2], AT_IntPtr, &namelen, sizeof(namelen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Bind, 3, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
free(psa);
return nReturn;
}
int pascal far _export
closesocket(SOCKET s)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Close, 1, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
RemoveSocket(pps); /* Assume success. Is this valid? */
return nReturn;
}
int pascal far _export
connect(SOCKET s, const struct sockaddr FAR *name, int namelen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
struct sockaddr *psa;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
psa = (struct sockaddr *) malloc(namelen);
memcpy(psa, name, namelen);
psa->sa_family = htons(psa->sa_family);
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_CARGS(pfaArgs[1], AT_GenPtr, psa, namelen );
INIT_ARGS(pfaArgs[2], AT_IntPtr, &namelen, sizeof(namelen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Connect, 3, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
free(psa);
if (nReturn != -1)
pps->iFlags |= PSF_CONNECT;
return nReturn;
}
int pascal far _export
ioctlsocket(SOCKET s, long cmd, u_long far * arg)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
switch(cmd)
{
case FIONBIO:
if (*arg)
pps->iFlags |= PSF_NONBLOCK;
else
pps->iFlags &= ~PSF_NONBLOCK;
break;
case FIONREAD:
if (pps->pdIn)
*arg = pps->pdIn->iLen - pps->pdIn->nUsed;
else
*arg = 0;
break;
case SIOCATMARK:
*(BOOL *) arg = 0;
break;
}
return 0;
}
int pascal far _export getpeername (SOCKET s, struct sockaddr FAR *name,
int FAR * namelen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!GetSocketInfo(s))
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_GenPtr, name, *namelen );
INIT_ARGS(pfaArgs[2], AT_IntPtr, namelen, sizeof(*namelen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_GetPeerName, 3, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
if (nReturn != -1)
name->sa_family = ntohs(name->sa_family);
return nReturn;
}
int pascal far _export getsockname (SOCKET s, struct sockaddr FAR *name,
int FAR * namelen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!GetSocketInfo(s))
return -1;
*namelen = sizeof(struct sockaddr_in); /* Just in case */
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_GenPtr, name, *namelen );
INIT_ARGS(pfaArgs[2], AT_IntPtr, namelen, sizeof(*namelen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_GetSockName, 3, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
if (nReturn != -1)
name->sa_family = ntohs(name->sa_family);
return nReturn;
}
int pascal far _export getsockopt (SOCKET s, int level, int optname,
char FAR * optval, int FAR *optlen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[5];
struct func_arg pfaReturn;
struct transmit_function tf;
long iOptVal;
short iOptLen;
iOptLen = sizeof(long);
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!GetSocketInfo(s))
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_Int, &level, sizeof(level) );
INIT_ARGS(pfaArgs[2], AT_Int, &optname, sizeof(optname) );
if (optname == SO_LINGER)
INIT_ARGS(pfaArgs[3], AT_GenPtr, optval, iOptLen );
else
INIT_ARGS(pfaArgs[3], AT_Int32Ptr, &iOptVal, iOptLen );
INIT_ARGS(pfaArgs[4], AT_IntPtr, &iOptLen, sizeof(iOptLen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_GetSockOpt, 5, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
if (optname == SO_LINGER)
{
*optlen = sizeof(struct linger);
}
else
{
*optlen = sizeof(int);
*optval = iOptVal;
}
}
return nReturn;
}
u_long pascal far _export htonl (u_long hostlong)
{
char *pchValue = (char *) &hostlong;
char c;
c = pchValue[0];
pchValue[0] = pchValue[3];
pchValue[3] = c;
c = pchValue[1];
pchValue[1] = pchValue[2];
pchValue[2] = c;
return hostlong;
}
u_short pascal far _export htons (u_short hostshort)
{
char *pchValue = (char *) &hostshort;
char c;
c = pchValue[0];
pchValue[0] = pchValue[1];
pchValue[1] = c;
return hostshort;
}
unsigned long pascal far _export inet_addr (const char FAR * cp)
{
unsigned long iValue;
char *pchValue = (char *) &iValue;
if (!GetTaskInfo())
return -1;
pchValue[0] = atoi(cp);
cp = strchr(cp, '.');
if (cp)
{
cp++;
pchValue[1] = atoi(cp);
cp = strchr(cp, '.');
if (cp)
{
cp++;
pchValue[2] = atoi(cp);
cp = strchr(cp, '.');
if (cp)
{
cp++;
pchValue[3] = atoi(cp);
cp = strchr(cp, '.');
if (!cp)
{
return iValue;
}
}
}
}
return -1;
}
char FAR * pascal far _export inet_ntoa (struct in_addr in)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
sprintf(ppt->achAddress, "%d.%d.%d.%d",
(int) in.S_un.S_un_b.s_b1,
(int) in.S_un.S_un_b.s_b2,
(int) in.S_un.S_un_b.s_b3,
(int) in.S_un.S_un_b.s_b4);
return ppt->achAddress;
}
int pascal far _export listen (SOCKET s, int backlog)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
if (pps->iFlags & PSF_CONNECT)
{
iErrno = WSAEISCONN;
return -1;
}
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_Int, &backlog, sizeof(backlog) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Listen, 2, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
if (nReturn != -1)
pps->iFlags |= PSF_ACCEPT;
return nReturn;
}
u_long pascal far _export ntohl (u_long netlong)
{
char *pchValue = (char *) &netlong;
char c;
c = pchValue[0];
pchValue[0] = pchValue[3];
pchValue[3] = c;
c = pchValue[1];
pchValue[1] = pchValue[2];
pchValue[2] = c;
return netlong;
}
u_short pascal far _export ntohs (u_short netshort)
{
char *pchValue = (char *) &netshort;
char c;
c = pchValue[0];
pchValue[0] = pchValue[1];
pchValue[1] = c;
return netshort;
}
int pascal far _export recv (SOCKET s, char FAR * buf, int len, int flags)
{
return recvfrom(s, buf, len, flags, 0, 0);
}
int pascal far _export recvfrom (SOCKET s, char FAR * buf, int len, int flags,
struct sockaddr FAR *from, int FAR * fromlen)
{
struct per_task *ppt;
struct per_socket *pps;
struct data *pd;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
if (pps->iFlags & PSF_CLOSED)
{
/* Haven't you got the message yet? */
iErrno = WSAENOTCONN;
return -1;
}
if (pps->iFlags & PSF_ACCEPT)
{
iErrno = WSAENOTCONN;
return -1;
}
if (pps->iFlags & PSF_SHUTDOWN)
{
iErrno = WSAESHUTDOWN;
return -1;
}
if (!pps->pdIn && (pps->iFlags & PSF_NONBLOCK))
{
iErrno = WSAEWOULDBLOCK;
return -1;
}
if (!StartBlocking(ppt))
return -1;
while (!pps->pdIn)
{
FlushMessages(ppt);
if (ppt->bCancel)
{
iErrno = WSAEINTR;
EndBlocking(ppt);
return -1;
}
}
pd = pps->pdIn;
if (from && fromlen)
{
memcpy(from, &pd->sin, sizeof(pd->sin));
*fromlen = sizeof(pd->sin);
}
if (len > pd->iLen - pd->nUsed)
len = pd->iLen - pd->nUsed;
memcpy(buf, pd->pchData + pd->nUsed, len);
pd->nUsed += len;
if (pd->nUsed == pd->iLen)
{
pps->pdIn = pd->pdNext;
free(pd->pchData);
free(pd);
if (pps->pdIn)
Notify(pps, pps->pdIn->iLen ? FD_READ : FD_CLOSE);
}
else
{
Notify(pps, FD_READ);
}
EndBlocking(ppt);
return len;
}
#define PPS_ERROR ((struct per_socket *) -1)
static struct per_socket **
GetPPS(fd_set *fds)
{
struct per_socket **pps;
int i;
if (!fds || !fds->fd_count)
return 0;
pps = (struct per_socket *) malloc(sizeof(struct per_socket *) *
fds->fd_count);
for (i = 0; i < fds->fd_count; i++)
{
pps[i] = GetSocketInfo(fds->fd_array[i]);
if (!pps[i])
{
free(pps);
return PPS_ERROR;
}
}
return pps;
}
int pascal far _export select (int nfds, fd_set *readfds, fd_set far *writefds,
fd_set *exceptfds, const struct timeval far *timeout)
{
struct per_task *ppt;
struct per_socket **ppsRead, **ppsWrite, **ppsExcept;
BOOL bOneOK = FALSE;
BOOL bTimedOut = FALSE;
int iOld, iNew;
unsigned long tExpire;
int i;
if (timeout)
{
tExpire = GetTickCount();
tExpire += timeout->tv_usec / 1000 + timeout->tv_sec * 1000;
}
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!StartBlocking(ppt))
return -1;
ppsRead = GetPPS(readfds);
if (ppsRead == PPS_ERROR)
return -1;
ppsWrite = GetPPS(writefds);
if (ppsWrite == PPS_ERROR)
{
free(ppsRead);
return -1;
}
ppsExcept = GetPPS(exceptfds);
if (ppsExcept == PPS_ERROR)
{
free(ppsRead);
free(ppsWrite);
return -1;
}
while (!bOneOK && !bTimedOut && !ppt->bCancel)
{
FlushMessages(ppt);
if (ppsWrite)
bOneOK = TRUE;
if (ppsRead)
{
for (i = 0; i < readfds->fd_count; i++)
{
if (ppsRead[i]->pdIn)
bOneOK = TRUE;
}
}
if (timeout && GetTickCount() >= tExpire)
bTimedOut = TRUE;
}
nfds = 0;
if (readfds)
{
for (iOld = iNew = 0; iOld < readfds->fd_count; iOld++)
{
if (iOld != iNew)
readfds->fd_array[iNew] =
readfds->fd_array[iOld];
if (ppsRead[iOld]->pdIn)
iNew++;
}
readfds->fd_count = iNew;
nfds += iNew;
}
if (writefds)
nfds += writefds->fd_count;
if (exceptfds)
exceptfds->fd_count = 0;
EndBlocking(ppt);
if (ppsRead)
free(ppsRead);
if (ppsWrite)
free(ppsWrite);
if (ppsExcept)
free(ppsExcept);
if (ppt->bCancel && !nfds)
{
iErrno = WSAEINTR;
return -1;
}
else
{
return nfds;
}
}
/* We don't wait for the result of a send because some telnets don't behave
* correctly with WSAEINPROGRESS when sending. This results in characters
* being dropped to hell while we wait for the response from the host.
* We return success unless the socket is not connected or is closed.
* This is fairly safe on connected sockets (which is what uses send).
*
* We don't do this with sendto because it's really only telnets that suffer
* from this, although that doesn't stop another application from having the
* same problem with sendto later on.
*
* This causes certain FTP clients to display phenomenal transfer rates.
* They should be checking the transfer rates *after* closing their sockets.
*/
int pascal far _export send (SOCKET s, const char FAR * buf, int len, int flags)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[4];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
if (!(pps->iFlags & PSF_CONNECT))
{
iErrno = WSAENOTCONN;
return -1;
}
if (pps->iFlags & PSF_CLOSED)
{
iErrno = WSAECONNRESET;
return -1;
}
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_CARGS(pfaArgs[1], AT_GenPtr, buf, len );
INIT_ARGS(pfaArgs[2], AT_IntPtr, &len, sizeof(len) );
INIT_ARGS(pfaArgs[3], AT_Int, &flags, sizeof(flags) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Send, 4, pfaArgs, pfaReturn);
RemoveTXQ(TransmitFunction(&tf));
Notify(pps, FD_WRITE);
return len;
}
int pascal far _export sendto (SOCKET s, const char FAR * buf, int len, int flags,
const struct sockaddr FAR *to, int tolen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[6];
struct func_arg pfaReturn;
struct transmit_function tf;
struct sockaddr *psa;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
psa = (struct sockaddr *) malloc(tolen);
memcpy(psa, to, tolen);
psa->sa_family = htons(psa->sa_family);
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_CARGS(pfaArgs[1], AT_GenPtr, buf, len );
INIT_ARGS(pfaArgs[2], AT_IntPtr, &len, sizeof(len) );
INIT_ARGS(pfaArgs[3], AT_Int, &flags, sizeof(flags) );
INIT_CARGS(pfaArgs[4], AT_GenPtr, to, tolen );
INIT_ARGS(pfaArgs[5], AT_Int, &tolen, sizeof(tolen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Send, 6, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
free(psa);
Notify(pps, FD_WRITE);
return nReturn;
}
int pascal far _export setsockopt (SOCKET s, int level, int optname,
const char FAR * optval, int optlen)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[5];
struct func_arg pfaReturn;
struct transmit_function tf;
long iOptVal;
short iOptLen;
iOptLen = sizeof(long);
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (!GetSocketInfo(s))
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_Int, &level, sizeof(level) );
INIT_ARGS(pfaArgs[2], AT_Int, &optname, sizeof(optname) );
if (optname == SO_LINGER)
{
INIT_ARGS(pfaArgs[3], AT_GenPtr, optval, iOptLen );
}
else
{
iOptVal = *optval;
INIT_ARGS(pfaArgs[3], AT_Int32Ptr, &iOptVal, iOptLen );
}
INIT_ARGS(pfaArgs[4], AT_Int, &iOptLen, sizeof(iOptLen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_SetSockOpt, 5, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
return nReturn;
}
int pascal far _export shutdown (SOCKET s, int how)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &s, sizeof(s) );
INIT_ARGS(pfaArgs[1], AT_Int, &how, sizeof(how) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Shutdown, 2, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
if (nReturn != -1 && (how == 0 || how == 2))
pps->iFlags |= PSF_SHUTDOWN;
return nReturn;
}
SOCKET pascal far _export socket (int af, int type, int protocol)
{
struct per_task *ppt;
struct per_socket *pps;
int nReturn;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
INIT_ARGS(pfaArgs[0], AT_Int, &af, sizeof(af) );
INIT_ARGS(pfaArgs[1], AT_Int, &type, sizeof(type) );
INIT_ARGS(pfaArgs[2], AT_Int, &protocol, sizeof(protocol) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_Socket, 3, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
if (nReturn != -1)
NewSocket(ppt, nReturn);
return nReturn;
}
struct hostent FAR * pascal far _export gethostbyaddr(const char FAR * addr,
int len, int type)
{
struct per_task *ppt;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_GenPtr, addr, len );
INIT_ARGS(pfaArgs[1], AT_Int, &len, sizeof(len) );
INIT_ARGS(pfaArgs[2], AT_Int, &type, sizeof(type) );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achHostEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_HostByAddr, 3, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyHostEnt(ppt);
return &ppt->he;
}
else
{
return 0;
}
}
struct hostent FAR * pascal far _export gethostbyname(const char FAR * name)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_String, name, strlen(name) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achHostEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_HostByName, 1, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyHostEnt(ppt);
return &ppt->he;
}
else
{
return 0;
}
}
struct servent FAR * pascal far _export getservbyport(int port, const char FAR * proto)
{
struct per_task *ppt;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
PORTSWAP(port);
if (!proto)
proto = "";
INIT_ARGS(pfaArgs[0], AT_Int, &port, sizeof(port) );
INIT_CARGS(pfaArgs[1], AT_String, proto, strlen(proto) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achServEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ServByPort, 2, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyServEnt(ppt);
return &ppt->se;
}
else
{
return 0;
}
}
struct servent FAR * pascal far _export getservbyname(const char FAR * name,
const char FAR * proto)
{
struct per_task *ppt;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
if (!proto)
proto = "";
INIT_CARGS(pfaArgs[0], AT_String, name, strlen(name) + 1 );
INIT_CARGS(pfaArgs[1], AT_String, proto, strlen(proto) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achServEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ServByName, 2, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyServEnt(ppt);
return &ppt->se;
}
else
{
return 0;
}
}
struct protoent FAR * pascal far _export getprotobynumber(int proto)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_ARGS(pfaArgs[0], AT_Int, &proto, sizeof(proto) );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achProtoEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ProtoByNumber, 1, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyProtoEnt(ppt);
return &ppt->pe;
}
else
{
return 0;
}
}
struct protoent FAR * pascal far _export getprotobyname(const char FAR * name)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_String, name, strlen(name) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achProtoEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ProtoByName, 1, pfaArgs, pfaReturn);
if (TransmitFunctionAndBlock(ppt, &tf))
{
CopyProtoEnt(ppt);
return &ppt->pe;
}
else
{
return 0;
}
}
int pascal far _export
gethostname(char *name, int namelen)
{
struct per_task *ppt;
int nReturn;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
if ((ppt = GetTaskInfo()) == 0)
return -1;
INIT_ARGS(pfaArgs[0], AT_String, name, namelen );
INIT_ARGS(pfaArgs[1], AT_Int, &namelen, sizeof(namelen) );
INIT_ARGS(pfaReturn, AT_Int, &nReturn, sizeof(nReturn) );
INIT_TF(tf, FN_GetHostName, 2, pfaArgs, pfaReturn);
TransmitFunctionAndBlock(ppt, &tf);
return nReturn;
}
int pascal far _export WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
{
struct per_task *pptNew;
lpWSAData->wVersion = 0x0101;
lpWSAData->wHighVersion = 0x0101;
strcpy(lpWSAData->szDescription,
"TwinSock 1.1 - Proxy sockets system. "
"Copyright 1994 Troy Rollo. "
"TwinSock is free software. "
"See the file \"COPYING\" from the "
"distribution for details.");
if (!hwndManager)
strcpy(lpWSAData->szSystemStatus, "Not Initialised.");
else if (bEstablished)
strcpy(lpWSAData->szSystemStatus, "Ready.");
else
strcpy(lpWSAData->szSystemStatus, "Initialising.");
lpWSAData->iMaxSockets = 256;
lpWSAData->iMaxUdpDg = 512;
lpWSAData->lpVendorInfo = 0;
if (wVersionRequired == 0x0001)
return WSAVERNOTSUPPORTED;
if (!bEstablished)
return WSASYSNOTREADY;
pptNew = malloc(sizeof(struct per_task));
pptNew->htask = GetCurrentTask();
pptNew->pptNext = pptList;
pptNew->lpBlockFunc = 0;
pptNew->bCancel = FALSE;
pptNew->bBlocking = FALSE;
pptList = pptNew;
return 0;
}
int pascal far _export WSACleanup(void)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (ppt->bBlocking)
{
iErrno = WSAEINPROGRESS;
RemoveTask(ppt);
return -1;
}
return 0;
}
void pascal far _export WSASetLastError(int iError)
{
if (!GetTaskInfo())
return -1;
iErrno = iError;
}
int pascal far _export WSAGetLastError(void)
{
return iErrno;
}
BOOL pascal far _export WSAIsBlocking(void)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
return ppt->bBlocking;
}
int pascal far _export WSAUnhookBlockingHook(void)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
ppt->lpBlockFunc = 0;
return 0;
}
FARPROC pascal far _export WSASetBlockingHook(FARPROC lpBlockFunc)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
ppt->lpBlockFunc = lpBlockFunc;
return -1;
}
int pascal far _export WSACancelBlockingCall(void)
{
struct per_task *ppt;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if (ppt->bBlocking)
{
ppt->bCancel = TRUE;
return 0;
}
else
{
iErrno = WSAEINVAL;
return -1;
}
}
static void
FireAsyncRequest(struct tx_queue *ptxq)
{
int nLen;
char *pchData;
struct per_task *ppt;
if (ptxq->ptxr->nError)
{
PostMessage(ptxq->hwnd, ptxq->wMsg, ptxq->id | 0x4000,
WSAMAKEASYNCREPLY(0, ntohs(ptxq->ptxr->nError)));
RemoveTXQ(ptxq);
return;
}
ppt = GetAnotherTaskInfo(ptxq->htask);
if (!ppt)
{
/* How **Rude** */
RemoveTXQ(ptxq);
return;
}
pchData = ptxq->ptxr->pchData +
ntohs(ptxq->ptxr->nLen) -
MAX_HOST_ENT -
sizeof(short) * 5;
switch(ptxq->ft)
{
case FN_HostByName:
case FN_HostByAddr:
memcpy(ppt->achHostEnt, pchData, MAX_HOST_ENT);
nLen = CopyHostEntTo(ppt, ptxq->pchLocation);
break;
case FN_ServByName:
case FN_ServByPort:
memcpy(ppt->achServEnt, pchData, MAX_HOST_ENT);
nLen = CopyServEntTo(ppt, ptxq->pchLocation);
break;
case FN_ProtoByName:
case FN_ProtoByNumber:
memcpy(ppt->achProtoEnt, pchData, MAX_HOST_ENT);
nLen = CopyProtoEntTo(ppt, ptxq->pchLocation);
break;
}
PostMessage(ptxq->hwnd, ptxq->wMsg, ptxq->id | 0x4000,
WSAMAKEASYNCREPLY(nLen, 0));
RemoveTXQ(ptxq);
}
HANDLE pascal far _export WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
const char FAR * name,
const char FAR * proto,
char FAR * buf, int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
if (!proto)
proto = "";
INIT_CARGS(pfaArgs[0], AT_String, name, strlen(name) + 1 );
INIT_CARGS(pfaArgs[1], AT_String, proto, strlen(proto) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achServEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ServByName, 2, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_ServByName;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
HANDLE pascal far _export WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
const char FAR * proto, char FAR * buf,
int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[2];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
port = PORTSWAP(port);
if (!proto)
proto = "";
INIT_CARGS(pfaArgs[0], AT_Int, &port, sizeof(port) );
INIT_CARGS(pfaArgs[1], AT_String, proto, strlen(proto) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achServEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ServByPort, 2, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_ServByPort;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
HANDLE pascal far _export WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
const char FAR * name, char FAR * buf,
int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_String, name, strlen(name) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achProtoEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ProtoByName, 1, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_ProtoByName;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
HANDLE pascal far _export WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
int number, char FAR * buf,
int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_Int, &number, sizeof(number) );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achProtoEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_ProtoByNumber, 1, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_ProtoByNumber;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
HANDLE pascal far _export WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
const char FAR * name, char FAR * buf,
int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[1];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_GenPtr, name, strlen(name) + 1 );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achHostEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_HostByName, 1, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_HostByName;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
HANDLE pascal far _export WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
const char FAR * addr, int len, int type,
char FAR * buf, int buflen)
{
struct per_task *ppt;
struct func_arg pfaArgs[3];
struct func_arg pfaReturn;
struct transmit_function tf;
struct tx_queue *txq;
if ((ppt = GetTaskInfo()) == 0)
return 0;
INIT_CARGS(pfaArgs[0], AT_GenPtr, addr, len );
INIT_CARGS(pfaArgs[1], AT_Int, &len, sizeof(len) );
INIT_CARGS(pfaArgs[2], AT_Int, &type, sizeof(type) );
INIT_ARGS(pfaReturn, AT_GenPtr, ppt->achHostEnt,MAX_HOST_ENT );
INIT_TF(tf, FN_HostByAddr, 3, pfaArgs, pfaReturn);
txq = TransmitFunction(&tf);
txq->hwnd = hWnd;
txq->pchLocation = buf;
txq->wMsg = wMsg;
txq->ft = FN_HostByAddr;
txq->htask = ppt->htask;
return (txq->id | 0x4000);
}
int pascal far _export WSACancelAsyncRequest(HANDLE hAsyncTaskHandle)
{
struct tx_queue *ptxq;
if (!GetTaskInfo())
return -1;
for (ptxq = ptxqList; ptxq; ptxq = ptxq->ptxqNext)
{
if ((HANDLE) (ptxq->id | 0x4000) == hAsyncTaskHandle)
{
RemoveTXQ(ptxq);
return 0;
}
}
iErrno = WSAEINVAL;
return -1;
}
int pascal far _export WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
long lEvent)
{
struct per_task *ppt;
struct per_socket *pps;
if ((ppt = GetTaskInfo()) == 0)
return -1;
if ((pps = GetSocketInfo(s)) == 0)
return -1;
if (lEvent)
pps->iFlags |= PSF_NONBLOCK;
pps->hWnd = hWnd;
pps->wMsg = wMsg;
pps->iEvents = lEvent;
Notify(pps, FD_WRITE);
if (pps->pdIn)
Notify(pps, (pps->iFlags & PSF_ACCEPT) ?
FD_ACCEPT :
(pps->pdIn->iLen ?
FD_READ :
FD_CLOSE));
return 0;
}
int FAR PASCAL _export _WSAFDIsSet(SOCKET s, fd_set FAR *pfds)
{
int i;
if (!GetTaskInfo())
return -1;
if (!GetSocketInfo(s))
return -1;
for (i = 0; i < pfds->fd_count; i++)
{
if (pfds->fd_array[i] == s)
return TRUE;
}
return FALSE;
}